﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Styx;
using Styx.CommonBot;
using Styx.CommonBot.Routines;
using Styx.Helpers;
using Styx.TreeSharp;
using Styx.WoWInternals;
using Styx.WoWInternals.WoWObjects;
using Action = Styx.TreeSharp.Action;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using Styx.Pathing;
using Styx.Common;
using System.Windows.Media;
using Styx.CommonBot.Frames;
using System.Diagnostics;

namespace Guardian
{
    public partial class Combat : CombatRoutine
    {
        

        #region next symbiosis allowed
        private DateTime nextSymbiosisCastAllowed;

        public void SetNexSymbiosisCastAllowed()
        {
            nextSymbiosisCastAllowed = DateTime.Now + new TimeSpan(0, 0, 0, 0, 2500);
        }
        #endregion

        #region next trinket use allowed
        private DateTime nextTrinketTimeAllowed;

        public void SetNextNextTrinketTimeAllowed()
        {
            nextTrinketTimeAllowed = DateTime.Now + new TimeSpan(0, 0, 0, 0, 5000);
        }
        #endregion

        #region next healthstone use allowed
        private DateTime nextHealthstoneUseAllowed;

        public void SetNextHealthstoneUseAllowed()
        {
            nextHealthstoneUseAllowed = DateTime.Now + new TimeSpan(0, 0, 1, 59, 0);
        }
        #endregion

        #region next healing touch
        private DateTime nextHealingTouchAllowed;

        public void SetNextHealingTouchAllowed()
        {
            nextHealingTouchAllowed = DateTime.Now + new TimeSpan(0, 0, 0, 0, 1000);
        }
        #endregion

        #region AutoBot
        bool AutoBot
        {
            get
            {
                return usedBot.Contains("QUEST") || usedBot.Contains("GRIND") || usedBot.Contains("GATHER") || usedBot.Contains("ANGLER");

            }
        }
        #endregion

        #region IsInRange
        public bool IsInRange(float range, WoWUnit target)
        {
            return target.Location.Distance(Me.Location) <= range;
        }
        #endregion

        #region can buff and eat
        public bool CanBuffEat
        {
            get
            {
                return !Me.Mounted && !Me.IsFlying && !Me.OnTaxi && !Me.IsDead && !Me.IsGhost;
            }
        }
        #endregion

        #region gotTarget
        public bool gotTarget
        {
            get
            {
                return Me.CurrentTarget != null && !Me.CurrentTarget.IsDead && !Me.CurrentTarget.IsFriendly && Me.CurrentTarget.Attackable && Me.CurrentTarget.CanSelect;
            }
        }
        #endregion

        #region spells
        string MAUL = "Maul";
        int MAUL_INT = 6807;
        string LACERATE = "Lacerate";
        string MANGLE = "Mangle";
        int MANGLE_INT = 33878;
        string SWIPE = "Swipe";
        string THRASH = "Thrash";
        string WILD_CHARGE = "Wild Charge";
        string FAERIE_FIRE = "Faerie Fire";
        string FAERIE_SWARM = "Faerie Swarm";
        string FORCE_OF_NATURE = "Force of Nature";
        string DREAM_OF_CENARIUS = "Dream of Cenarius";
        string BERSERK = "Berserk";
        string GROWL = "Growl";
        string BEAR_FORM = "Bear Form";
        string CAT_FORM = "Cat Form";
        string BEAR_HUG = "Bear Hug";
        string HEALING_TOUCH = "Healing Touch";
        int HEALING_TOUCH_INT = 5185;
        string REJUVENATION = "Rejuvenation";
        string SKULL_BASH = "Skull Bash";
        string MIGHTY_BASH = "Mighty Bash";
        string WAR_STOMP = "War Stomp";
        string ENRAGE = "Enrage";
        string CYCLONE = "Cyclone";
        string INCARNATION = "Incarnation";
        string BARKSKIN = "Barkskin";
        string FRENZIED_REGENERATION = "Frenzied Regeneration";
        string SURVIVAL_INSTINCTS = "Survival Instincts";
        string MIGHT_OF_URSOC = "Might of Ursoc";
        string SAVAGE_DEFENSE = "Savage Defense";
        int SAVAGE_DEFENSE_INT = 62606;
        string MOTW = "Mark of the Wild";
        string TOOTH_AND_CLAW = "Tooth and Claw";
        string REBIRTH = "Rebirth";
        int REBIRTH_INT = 20484;
        string RAKE = "Rake";
        string SAVAGE_ROAR = "Savage Roar";
        string LIFEBLOOD = "Lifeblood";
        string TIGERS_FURY = "Tiger's Fury";
        string TIME_WARP = "Time Warp";
        string HEROISM = "Heroism";
        string BLOODLUST = "Bloodlust";
        string DRUMS_OF_RAGE = "Drums of Rage";
        string BERSERKING = "Berserking";
        string ANCIENT_HYSTERIA = "Ancient Hysteria";
        string RIP = "Rip";
        string CLEARCASTING = "Clearcasting";
        string FEROCIOUS_BITE = "Ferocious Bite";
        string RAVAGE = "Ravage";
        string SHRED = "Shred";
        string PREDATORY_SWIFTNESS = "Predatory Swiftness";
        string WRATH = "Wrath";
        string MOONFIRE = "Moonfire";

        #endregion

        #region hastebuffs
        public bool NotHaveHasteBuffs
        {
            get
            {
                return !buffExists(TIGERS_FURY, Me)
                    && !buffExists(HEROISM, Me)
                    && !buffExists(TIME_WARP, Me)
                    && !buffExists(BLOODLUST, Me)
                    && !buffExists(DRUMS_OF_RAGE, Me)
                    && !buffExists(ANCIENT_HYSTERIA, Me);
            }
        }
        #endregion

        #region overlayed
        public bool IsOverlayed(int spellID)
        {
            return Lua.GetReturnVal<bool>("return IsSpellOverlayed(" + spellID + ")", 0);
        }
        #endregion overlayed

        #region spellcharges
        public static double GetSpellCharges(int spellID)
        {
            return Lua.GetReturnVal<int>("return GetSpellCharges(" + spellID + ")", 0);
        }
        #endregion

        #region spellcasting
        public delegate T Selection<out T>(object context);

        Composite Cast(string spell, Selection<bool> reqs = null)
        {
            return
                new Decorator(
                    ret => ((reqs != null && reqs(ret)) || (reqs == null)) && SpellManager.CanCast(spell),
                    new Action(ret =>
                    {
                        SpellManager.Cast(spell);
                        Logging.Write(spell);
                        LastSpell = spell;
                    }
                        ));
        }
        Composite CastOnMe(string spell, Selection<bool> reqs = null)
        {
            return
                new Decorator(
                    ret => ((reqs != null && reqs(ret)) || (reqs == null)) && SpellManager.CanCast(spell),
                    new Action(ret =>
                    {
                        SpellManager.Cast(spell, Me);
                        Logging.Write(spell);
                        LastSpell = spell;
                    }
                        ));
        }

        public static TimeSpan GetSpellCooldown(string spell)
        {
            SpellFindResults results;
            if (SpellManager.FindSpell(spell, out results))
            {
                if (results.Override != null)
                    return results.Override.CooldownTimeLeft;
                return results.Original.CooldownTimeLeft;
            }


            return TimeSpan.MaxValue;
        }
        #endregion

        #region addcount
        IEnumerable<WoWUnit> UnfriendlyUnits
        {
            get { return ObjectManager.GetObjectsOfType<WoWUnit>(true, false).Where(u => u != null && !u.IsDead && u.CanSelect && u.Attackable && !u.IsFriendly && u.IsWithinMeleeRange); }
        }
        #endregion

        #region movement targeting facing
        [DllImport("user32.dll")]
        private static extern short GetAsyncKeyState(Keys vKey);

        public bool AllowFacing
        {
            get
            {
                if (SettingsCommon.myPrefs.AutoFacingRaid
                    && (Me.GroupInfo.IsInRaid || Me.CurrentMap.IsInstance || Me.CurrentMap.IsRaid))
                {
                    return false;
                }
                if ((GetAsyncKeyState(Keys.LButton) != 0
                    && GetAsyncKeyState(Keys.RButton) != 0) ||
                    GetAsyncKeyState(Keys.W) != 0 ||
                    GetAsyncKeyState(Keys.S) != 0 ||
                    GetAsyncKeyState(Keys.D) != 0 ||
                    GetAsyncKeyState(Keys.A) != 0)
                {
                    return false;
                }
                return SettingsCommon.myPrefs.AutoFacing;

            }
        }
        public bool AllowTargeting
        {
            get
            {
                if (SettingsCommon.myPrefs.AutoTargetingRaid
                    && (Me.GroupInfo.IsInRaid || Me.CurrentMap.IsInstance || Me.CurrentMap.IsRaid))
                {
                    return false;
                }
                if ((GetAsyncKeyState(Keys.LButton) != 0
                    && GetAsyncKeyState(Keys.RButton) != 0) ||
                    GetAsyncKeyState(Keys.W) != 0 ||
                    GetAsyncKeyState(Keys.S) != 0 ||
                    GetAsyncKeyState(Keys.D) != 0 ||
                    GetAsyncKeyState(Keys.A) != 0)
                {
                    return false;
                }
                return SettingsCommon.myPrefs.AutoTargeting;
            }
        }
        public bool AllowMovement
        {
            get
            {
                if (SettingsCommon.myPrefs.AutoMovementRaid
                    && (Me.GroupInfo.IsInRaid || Me.CurrentMap.IsInstance || Me.CurrentMap.IsRaid))
                {
                    return false;
                }
                if ((GetAsyncKeyState(Keys.LButton) != 0
                    && GetAsyncKeyState(Keys.RButton) != 0) ||
                    GetAsyncKeyState(Keys.W) != 0 ||
                    GetAsyncKeyState(Keys.S) != 0 ||
                    GetAsyncKeyState(Keys.D) != 0 ||
                    GetAsyncKeyState(Keys.A) != 0)
                {
                    return false;
                }


                return SettingsCommon.myPrefs.AutoMovement;
            }
        }

        Composite CreateMovementBehavior()
        {
            return
                    new Action(ret =>
                    {
                        Navigator.MoveTo(StyxWoW.Me.CurrentTarget.Location);
                        return RunStatus.Failure;
                    }
                );
        }
        Composite CreateStopMovement()
        {
            return new Action(ret =>
            {
                Navigator.PlayerMover.MoveStop();
                return RunStatus.Failure;
            });
        }
        Composite CreateMoveBackBehavior()
        {
            return new Action(ret =>
            {
                WoWMovement.Move(WoWMovement.MovementDirection.Backwards);
                while (gotTarget && Me.CurrentTarget.IsAlive && Me.CurrentTarget.Distance < 10)
                {
                    break;
                }
                Navigator.PlayerMover.MoveStop();
                return RunStatus.Failure;
            });
        }
        float myRange
        {
            get
            {
                if ((Me.CurrentTarget != null && Me.CurrentTarget.IsPlayer)) { return 1.5f; }
                return 3.5f;
            }
        }
        public bool NeedGoBackwards
        {
            get
            {
                return Me.CurrentTarget != null && (Me.CurrentTarget.IsCasting && Me.CurrentTarget.CastingSpell.ToString() == "Blazing Cleave");
            }
        }
        #endregion

        #region facing
        Composite FaceMyTarget()
        {
            return
                new Action(ret =>
                {
                    Me.CurrentTarget.Face();
                    return RunStatus.Failure;
                });
        }
        #endregion

        #region pause
        public static bool PauseAoe = false;
        public static bool Paused = false;
        public static bool SwitchBearForm = false;

        public static void HandleModifierStateChanged(object sender, LuaEventArgs args)
        {
            if (SettingsCommon.myPrefs.StopCRKey == SettingsCommon.Keypress.NONE
                && SettingsCommon.myPrefs.StopAoeKey == SettingsCommon.Keypress.NONE
                && SettingsCommon.myPrefs.BearFormKeys == SettingsCommon.Keypress.NONE)
            {
                return;
            }
            if (Convert.ToInt32(args.Args[1]) == 1)
            {
                string pauseMyAoe = "AOE cancelled, press " + SettingsCommon.myPrefs.StopAoeKey.ToString() + " in WOW again to turn AOE back on";
                if (args.Args[0].ToString() == SettingsCommon.myPrefs.StopAoeKey.ToString())
                {
                    PauseAoe = !PauseAoe;
                    if (PauseAoe)
                    {
                        Logging.Write("Aoe cancelled, press {0} in WOW again to resume Aoe",
                                     SettingsCommon.myPrefs.StopAoeKey.ToString());
                        if (SettingsCommon.myPrefs.PrintRaidstyleMsg)
                            Lua.DoString(
                                "RaidNotice_AddMessage(RaidWarningFrame, \"" + pauseMyAoe + "\", ChatTypeInfo[\"RAID_WARNING\"]);");
                    }
                    else
                    {
                        Logging.Write("Aoe Resumed");
                        if (SettingsCommon.myPrefs.PrintRaidstyleMsg)
                            Lua.DoString(
                                "RaidNotice_AddMessage(RaidWarningFrame, \"Aoe Resumed !\", ChatTypeInfo[\"RAID_WARNING\"]);");
                    }
                }
            }
            if (Convert.ToInt32(args.Args[1]) == 1)
            {
                if (args.Args[0].ToString() == SettingsCommon.myPrefs.StopCRKey.ToString())
                {
                    string pauseCR = "CR paused, press " + SettingsCommon.myPrefs.StopCRKey.ToString() + " in WOW again to turn back on";
                    Paused = !Paused;
                    if (Paused)
                    {
                        Logging.Write("CR paused, press {0} in WOW again to turn back on",
                                     SettingsCommon.myPrefs.StopCRKey.ToString());
                        if (SettingsCommon.myPrefs.PrintRaidstyleMsg)
                            Lua.DoString(
                                "RaidNotice_AddMessage(RaidWarningFrame, \"" + pauseCR + "\", ChatTypeInfo[\"RAID_WARNING\"]);");
                    }
                    else
                    {
                        Logging.Write("CR running again ....");
                        if (SettingsCommon.myPrefs.PrintRaidstyleMsg)
                            Lua.DoString(
                                "RaidNotice_AddMessage(RaidWarningFrame, \"CR running again ....\", ChatTypeInfo[\"RAID_WARNING\"]);");
                    }
                }
            }
            if (Convert.ToInt32(args.Args[1]) == 1)
            {
                if (args.Args[0].ToString() == SettingsCommon.myPrefs.BearFormKeys.ToString())
                {
                    SwitchBearForm = !SwitchBearForm;
                    if (SwitchBearForm)
                    {
                        string backBear = "Switching to Bear Form, press " + SettingsCommon.myPrefs.BearFormKeys.ToString() + " in WOW again to switch back to Cat Form";

                        Logging.Write("Switching to Bear Form, press {0} in WOW again to switch back to Cat Form",
                                     SettingsCommon.myPrefs.BearFormKeys.ToString());
                        if (SettingsCommon.myPrefs.PrintRaidstyleMsg)
                            Lua.DoString(
                                "RaidNotice_AddMessage(RaidWarningFrame, \"" + backBear + "\", ChatTypeInfo[\"RAID_WARNING\"]);");
                    }
                    else
                    {
                        Logging.Write("Switching back to Cat Form !");
                        if (SettingsCommon.myPrefs.PrintRaidstyleMsg)
                            Lua.DoString(
                                "RaidNotice_AddMessage(RaidWarningFrame, \"Switching back to Cat Form !\", ChatTypeInfo[\"RAID_WARNING\"]);");
                    }
                }
            }
        }
        #endregion pause

        #region loot

        private double LootRange
        {
            get { return LootTargeting.LootRadius; }
        }
        private IOrderedEnumerable<WoWUnit> Lootables
        {
            get
            {
                var targetsList = ObjectManager.GetObjectsOfType<WoWUnit>(false, false).Where(
                        p => (p.Lootable || p.CanSkin) && p.Distance <= LootRange).OrderBy(l => l.Distance);
                return targetsList;
            }
        }
        private void GetLoot()
        {
            if (Me.IsCasting || Lootables.Count() == 0)
                return;
            if (LootFrame.Instance != null && LootFrame.Instance.IsVisible)
            {
                LootFrame.Instance.LootAll();
                if (Me.CurrentTarget != null && Me.CurrentTarget.IsDead)
                {
                    Me.ClearTarget();
                }
                return;
            }
            var lootTarget = Lootables.FirstOrDefault();
            if (lootTarget.Distance > lootTarget.InteractRange && AutoBot)
            {
                Logging.Write("Moving to loot {0}.", lootTarget.Name);
                Navigator.MoveTo(lootTarget.Location);
            }
            else
            {
                lootTarget.Interact();
                if (Me.CurrentTarget != null && Me.CurrentTarget.IsDead)
                {
                    Me.ClearTarget();
                }
                return;
            }
        }
        Composite GetMyLoot()
        {
            return new Action(ret =>
            {
                if (LootFrame.Instance != null && LootFrame.Instance.IsVisible)
                {
                    LootFrame.Instance.LootAll();
                    return RunStatus.Failure;
                }
                var lootTarget = Lootables.FirstOrDefault();
                if (lootTarget.Distance > lootTarget.InteractRange && AutoBot)
                {
                    Logging.Write("Moving to loot {0}.", lootTarget.Name);
                    Navigator.MoveTo(lootTarget.Location);
                }
                else
                {
                    lootTarget.Interact();
                    return RunStatus.Failure;
                }
                return RunStatus.Failure;
            });
        }
        #endregion loot

        #region FindTarget
        WoWUnit FindTarget()
        {
            WoWUnit myTarget = ObjectManager.GetObjectsOfType<WoWUnit>(true, false).Where(u => ValidUnit(u)
                && (!u.OwnedByRoot.IsPlayer || u.OwnedByRoot.IsMe)
                && u.DistanceSqr <= 8 * 8
                && !Blacklist.Contains(u, BlacklistFlags.All))
                .OrderBy(u => u.IsPlayer)
                .ThenBy(u => u.Distance)
                .FirstOrDefault();
            if (myTarget != null)
            {
                Logging.Write(Colors.PaleGreen, "Found new Target " + myTarget.Name);
                myTarget.Target();
                return myTarget;
            }
            return null;
        }
        #endregion

        #region solo

        public bool MeIsSolo
        {
            get
            {
                return !Me.CurrentMap.IsRaid
                    && !Me.CurrentMap.IsDungeon
                    && !Me.CurrentMap.IsScenario
                    && !Me.CurrentMap.IsInstance
                    && !Me.GroupInfo.IsInRaid
                    && !Me.GroupInfo.IsInParty
                    && !Me.CurrentMap.IsArena
                    && !Me.CurrentMap.IsBattleground;
            }
        }
        #endregion

        #region members to heal
        Composite CastHealingTouch()
        {
            return new Action(ret =>
            {
                if (SpellManager.CanCast(HEALING_TOUCH))
                {
                    SpellManager.Cast(HEALING_TOUCH, Me);
                    Logging.Write(Colors.AliceBlue, HEALING_TOUCH);
                    SetNextHealingTouchAllowed();
                    return RunStatus.Success;
                }
                return RunStatus.Failure;
            });
        }
        Composite HealPartyMember()
        {
            return
                new Action(ret =>
                {
                    var myHealTarget = HealTarget();
                    if (myHealTarget != null && myHealTarget.IsAlive && SpellManager.CanCast(HEALING_TOUCH))
                    {
                        SpellManager.Cast(HEALING_TOUCH, myHealTarget);
                        Logging.Write(Colors.BlanchedAlmond, "Healing " + myHealTarget.Name + " with Healing Touch proc");
                        SetNextHealingTouchAllowed();
                        return RunStatus.Success;
                    }
                    return RunStatus.Failure;
                });
        }
        public static IEnumerable<WoWPlayer> HealMembers
        {
            get
            {
                ulong[] guids =
                    StyxWoW.Me.GroupInfo.RaidMemberGuids.Union(StyxWoW.Me.GroupInfo.PartyMemberGuids)
                        .Union(new[] { StyxWoW.Me.Guid })
                        .Distinct()
                        .ToArray();

                return (
                    from p in ObjectManager.GetObjectsOfType<WoWPlayer>(true, true)
                    where p.IsFriendly && guids.Any(g => g == p.Guid)
                    select p).ToList();
            }
        }
        public static IEnumerable<WoWPlayer> NearbyHealMembers
        {
            get
            {
                return HealMembers.Where(p => p.DistanceSqr <= 35 * 35)
                    .OrderBy(p => p.HealthPercent)
                    .ThenBy(p => p.Distance)
                    .ToList();
            }
        }
        private static WoWPlayer HealTarget()
        {
            return NearbyHealMembers.FirstOrDefault();
        }
        #endregion members to heal

        #region symbiosis

        Composite CastBearSymbiosis()
        {
            return new Action(ret =>
            {
                WoWPlayer symtarget = SymbiosisBearTarget();
                if (symtarget != null && symtarget != StyxWoW.Me)
                {
                    Symbiosis(symtarget);
                    return RunStatus.Success;
                }
                return RunStatus.Failure;
            });
        }
        Composite CastCatSymbiosis()
        {
            return new Action(ret =>
            {
                WoWPlayer symtarget = SymbiosisCatTarget();
                if (symtarget != null && symtarget != StyxWoW.Me)
                {
                    Symbiosis(symtarget);
                    return RunStatus.Success;
                }
                return RunStatus.Failure;
            });
        }
        public static IEnumerable<WoWPlayer> GroupMembers
        {
            get
            {
                ulong[] guids =
                    StyxWoW.Me.GroupInfo.RaidMemberGuids.Union(StyxWoW.Me.GroupInfo.PartyMemberGuids)
                        .Union(new[] { StyxWoW.Me.Guid })
                        .Distinct()
                        .ToArray();

                return (
                    from p in ObjectManager.GetObjectsOfType<WoWPlayer>(true, true)
                    where p.IsFriendly && guids.Any(g => g == p.Guid)
                    select p).ToList();
            }
        }

        public static IEnumerable<WoWPlayer> NearbyGroupMembers
        {
            get { return GroupMembers.Where(p => p.DistanceSqr <= 30 * 30).ToList(); }
        }


        private static WoWPlayer SymbiosisBearTarget()
        {
            if (!SpellManager.HasSpell("Symbiosis"))
                return null;
            return NearbyGroupMembers.FirstOrDefault(
                p => IsValidSymbiosisTarget(p) && p.Class == WoWClass.DeathKnight) // Bone Shield
                   ??
                   (NearbyGroupMembers.FirstOrDefault(
                       p => IsValidSymbiosisTarget(p) && p.Class == WoWClass.Paladin) // Consecration
                    ??
                    (NearbyGroupMembers.FirstOrDefault(
                        p => IsValidSymbiosisTarget(p) && p.Class == WoWClass.Shaman) // Lightning Shield
                     ?? (NearbyGroupMembers.FirstOrDefault(
                         p => IsValidSymbiosisTarget(p) && p.Class == WoWClass.Monk) // ElusiveBrew
                         )
                        )
                       );
        }
        private static WoWPlayer SymbiosisCatTarget()
        {
            if (!SpellManager.HasSpell("Symbiosis"))
                return null;
            return NearbyGroupMembers.FirstOrDefault(
                        p => IsValidSymbiosisTarget(p) && p.Class == WoWClass.Shaman)
                            ?? (NearbyGroupMembers.FirstOrDefault(
                                    p => IsValidSymbiosisTarget(p) && p.Class == WoWClass.Monk)
                            ??
                                (NearbyGroupMembers.FirstOrDefault(
                                    p => IsValidSymbiosisTarget(p) && p.Class == WoWClass.Paladin)
                            ??
                                (NearbyGroupMembers.FirstOrDefault(
                                    p => IsValidSymbiosisTarget(p) && p.Class == WoWClass.Priest)
                            ??
                                (NearbyGroupMembers.FirstOrDefault(
                                    p => IsValidSymbiosisTarget(p) && p.Class == WoWClass.DeathKnight)
                                    )
                                )
                            )
                       );
        }
        private static void Symbiosis(WoWUnit unit)
        {

            if (StyxWoW.Me.CurrentTarget != unit)
            {
                unit.Target();
                return;
            }
            SpellManager.Cast(110309, unit);
            Logging.Write(Colors.ForestGreen, "Casting Symbiosis on " + unit.Name);
            if (StyxWoW.Me.HasAura(110309))
                StyxWoW.Me.ClearTarget();
        }

        public static bool IsValidSymbiosisTarget(WoWPlayer p)
        {
            if (p == null)
                return false;

            if (p.IsHorde != StyxWoW.Me.IsHorde)
                return false;

            if (Blacklist.Contains(p.Guid, BlacklistFlags.Combat))
                return false;

            if (!p.IsAlive)
                return false;

            if (p.Level < 87)
                return false;

            if (p.Combat)
                return false;

            if (p.Distance > 28)
                return false;

            return !p.HasAura("Symbiosis") && p.InLineOfSpellSight;
        }
        #endregion

        #region rooted
        Composite RemoveRooted()
        {
            return
                    new Action(ret =>
                    {
                        if (Me.Shapeshift == ShapeshiftForm.Cat)
                        {
                            Lua.DoString("RunMacroText(\"/Cast !Cat Form\")");
                        }
                        if (Me.Shapeshift == ShapeshiftForm.Bear)
                        {
                            Lua.DoString("RunMacroText(\"/Cast !Bear Form\")");
                        }
                        return RunStatus.Failure;
                    });
        }
        #endregion

        #region crowdcontrol

        public bool IsCrowdControlledTarget(WoWUnit unit)
        {
            Dictionary<string, WoWAura>.ValueCollection auras = unit.Auras.Values;

            return unit.Fleeing
                || HasAuraWithEffect(unit,
                        WoWApplyAuraType.ModConfuse,
                        WoWApplyAuraType.ModCharm,
                        WoWApplyAuraType.ModFear,
                        WoWApplyAuraType.ModPossess);
        }

        public bool IsCrowdControlledPlayer(WoWUnit unit)
        {
            Dictionary<string, WoWAura>.ValueCollection auras = unit.Auras.Values;

            return unit.Rooted
                || unit.Fleeing
                || HasAuraWithEffect(unit,
                        WoWApplyAuraType.ModConfuse,
                        WoWApplyAuraType.ModCharm,
                        WoWApplyAuraType.ModFear,
                        WoWApplyAuraType.ModDecreaseSpeed,
                        WoWApplyAuraType.ModPacify,
                        WoWApplyAuraType.ModPacifySilence,
                        WoWApplyAuraType.ModPossess,
                        WoWApplyAuraType.ModRoot);
        }
        public bool IsRooted(WoWUnit unit)
        {
            Dictionary<string, WoWAura>.ValueCollection auras = unit.Auras.Values;

            return unit.Rooted;
        }
        // this one optimized for single applytype lookup
        public bool HasAuraWithEffect(WoWUnit unit, WoWApplyAuraType applyType)
        {
            return unit.Auras.Values.Any(a => a.Spell != null && a.Spell.SpellEffects.Any(se => applyType == se.AuraType));
        }

        public static bool HasAuraWithEffect(WoWUnit unit, params WoWApplyAuraType[] applyType)
        {
            var hashes = new HashSet<WoWApplyAuraType>(applyType);
            return unit.Auras.Values.Any(a => a.Spell != null && a.Spell.SpellEffects.Any(se => hashes.Contains(se.AuraType)));
        }
        #endregion

        #region autoattack
        Composite AutoAttack()
        {
            return new Action(ret =>
            {
                Lua.DoString("StartAttack()");
                return RunStatus.Failure;
            });
        }
        #endregion

        #region paused pauseAoe
        Composite PauseCR()
        {
            return new Action(ret =>
            {
                return;
            });
        }
        #endregion

        #region Kind of target
        public bool IsWoWBoss(WoWUnit mytarget)
        {
            if (StyxWoW.Me.CurrentTarget != null)
            {
                if (StyxWoW.Me.CurrentTarget.CreatureRank == WoWUnitClassificationType.WorldBoss)
                {
                    return true;
                }
                else if (target.IsBoss(mytarget))
                {
                    return true;
                }
                else if (Me.CurrentTarget.MaxHealth >= (100 * 1000000)) { return true; }
                else if (StyxWoW.Me.CurrentTarget.CreatureRank == WoWUnitClassificationType.RareElite
                    && StyxWoW.Me.CurrentTarget.MaxHealth >= (StyxWoW.Me.MaxHealth * 3)
                    && (!StyxWoW.Me.GroupInfo.IsInParty
                    || StyxWoW.Me.GroupInfo.NumPartyMembers <= 3)
                    && !StyxWoW.Me.GroupInfo.IsInRaid
                    && !StyxWoW.Me.IsInInstance)
                {
                    return true;
                }
                else if (StyxWoW.Me.CurrentTarget.CreatureRank == WoWUnitClassificationType.Rare
                    && StyxWoW.Me.CurrentTarget.MaxHealth >= (StyxWoW.Me.MaxHealth * 3)
                    && (!StyxWoW.Me.GroupInfo.IsInParty
                    || StyxWoW.Me.GroupInfo.NumPartyMembers <= 3)
                    && !StyxWoW.Me.GroupInfo.IsInRaid
                    && !StyxWoW.Me.IsInInstance)
                {
                    return true;
                }
                else if (StyxWoW.Me.CurrentTarget.CreatureRank == WoWUnitClassificationType.Elite
                    && StyxWoW.Me.CurrentTarget.MaxHealth >= (StyxWoW.Me.MaxHealth * 3)
                    && (!StyxWoW.Me.GroupInfo.IsInParty
                    || StyxWoW.Me.GroupInfo.NumPartyMembers <= 3)
                    && !StyxWoW.Me.GroupInfo.IsInRaid
                    && !StyxWoW.Me.IsInInstance)
                {
                    return true;
                }
                else if (StyxWoW.Me.CurrentTarget.Name.Contains("Dummy")
                    && !StyxWoW.Me.IsInInstance)
                {
                    return true;
                }
                else if (StyxWoW.Me.CurrentTarget.IsPlayer
                    && !StyxWoW.Me.CurrentTarget.IsFriendly)
                {
                    return true;
                }
            }
            return false;
        }
        #endregion Kind of Target

        #region valid units
        public bool ValidUnit(WoWUnit p)
        {
            if (p == null || !p.IsValid)
                return false;

            // Ignore shit we can't select
            if (!p.CanSelect)
            {
                return false;
            }

            // Ignore shit we can't attack
            if (!p.Attackable)
            {
                return false;
            }

            // Duh
            if (p.IsDead)
            {
                return false;
            }

            // check for enemy players here as friendly only seems to work on npc's
            if (p.IsPlayer)
            {
                WoWPlayer pp = p.ToPlayer();
                if (pp.IsHorde == StyxWoW.Me.IsHorde)
                {
                    return false;
                }

                if (pp.Guid == StyxWoW.Me.CurrentTargetGuid && CanAttackCurrentTarget)
                {
                    return false;
                }

                return true;
            }

            // Ignore friendlies!
            if (p.IsFriendly)
            {
                return false;
            }
            // If it is a pet/minion/totem, lets find the root of ownership chain
            WoWPlayer pOwner = GetPlayerParent(p);

            // ignore if owner is player, alive, and not blacklisted then ignore (since killing owner kills it)
            // .. following .IsMe check to prevent treating quest mob summoned by us that we need to kill as invalid 
            if (pOwner != null && pOwner.IsAlive && !pOwner.IsMe)
            {
                if (!ValidUnit(pOwner))
                {
                    return false;
                }
                if (!Blacklist.Contains(pOwner, BlacklistFlags.Combat))
                {
                    return false;
                }
                if (!StyxWoW.Me.IsPvPFlagged)
                {
                    return false;
                }
            }

            // And ignore critters (except for those ferocious ones) /non-combat pets
            if (p.IsNonCombatPet)
            {
                return false;
            }

            // And ignore critters (except for those ferocious ones) /non-combat pets
            if (p.IsCritter && p.ThreatInfo.ThreatValue == 0 && !p.IsTargetingMyRaidMember)
            {
                return false;
            }
            /*
                        if (p.CreatedByUnitGuid != 0 || p.SummonedByUnitGuid != 0)
                            return false;
            */
            return true;
        }

        public WoWPlayer GetPlayerParent(WoWUnit unit)
        {
            // If it is a pet/minion/totem, lets find the root of ownership chain
            WoWUnit pOwner = unit;
            while (true)
            {
                if (pOwner.OwnedByUnit != null)
                    pOwner = pOwner.OwnedByRoot;
                else if (pOwner.CreatedByUnit != null)
                    pOwner = pOwner.CreatedByUnit;
                else if (pOwner.SummonedByUnit != null)
                    pOwner = pOwner.SummonedByUnit;
                else
                    break;
            }

            if (unit != pOwner && pOwner.IsPlayer)
                return pOwner as WoWPlayer;

            return null;
        }
        public bool CanAttackCurrentTarget
        {
            get
            {
                if (StyxWoW.Me.CurrentTarget == null)
                    return false;

                return Lua.GetReturnVal<bool>("return UnitCanAttack(\"player\",\"target\")", 0);
            }
        }
        #endregion

        #region eatfood
        Composite EatFood()
        {
               return new Action(ret =>
                {
                    Styx.CommonBot.Rest.Feed();
                    return RunStatus.Failure;
                });
        }
        #endregion

        #region force of nature
        private DateTime nextFoNCastAllowed;

        public void SetNexFoNCastAllowed()
        {
            nextFoNCastAllowed = DateTime.Now + new TimeSpan(0, 0, 0, 0, 15000);
        }
        Composite CastFoN()
        {
            return new Action(ret =>
            {
                if (SpellManager.CanCast(FORCE_OF_NATURE) && targetExistence(Me.CurrentTarget) > 15)
                {
                    SpellManager.Cast(FORCE_OF_NATURE);
                    Logging.Write(Colors.Cornsilk, FORCE_OF_NATURE);
                    SetNexFoNCastAllowed();
                    return RunStatus.Success;
                }
                return RunStatus.Failure;
            });
        }
        #endregion

        #region rebirth
        private DateTime nextRebirthAllowed;

        public void SetNextRebirthAllowed()
        {
            nextRebirthAllowed = DateTime.Now + new TimeSpan(0, 0, 0, 0, 1000);
        }
        public static List<WoWPlayer> Tanks
        {
            get
            {
                if (!StyxWoW.Me.GroupInfo.IsInParty)
                    return new List<WoWPlayer>(); ;

                return StyxWoW.Me.GroupInfo.RaidMembers.Where(p => p.HasRole(WoWPartyMember.GroupRole.Tank))
                    .Select(p => p.ToPlayer())
                    .Union(new[] { RaFHelper.Leader })
                    .Where(p => p != null && p.IsDead)
                    .Distinct()
                    .ToList();
            }
        }

        public static List<WoWPlayer> Healers
        {
            get
            {
                if (!StyxWoW.Me.GroupInfo.IsInParty)
                    return new List<WoWPlayer>(); ;

                return StyxWoW.Me.GroupInfo.RaidMembers.Where(p => p.HasRole(WoWPartyMember.GroupRole.Healer))
                    .Select(p => p.ToPlayer()).Where(p => p != null && p.IsDead).ToList();

            }
        }
        public static bool AnyTankNearby
        {
            get
            {
                return Tanks.Any(h => h.IsDead && h.Distance < 40);
            }
        }
        public static bool AnyHealerNearby
        {
            get
            {
                return Healers.Any(h => h.IsDead && h.Distance < 40);
            }
        }
        Composite ResTank()
        {
            return
                new Action(ret =>
                {
                    var ResTankTarget = Tanks.FirstOrDefault();
                    string msg = StyxWoW.Me + " is ressing " + ResTankTarget;
                    if (ResTankTarget != null && SpellManager.CanCast(REBIRTH))
                    {
                        SpellManager.Cast(REBIRTH, ResTankTarget);
                        Logging.Write(Colors.Red, "Ressing Tank " + ResTankTarget.Name);
                        Lua.DoString("RunMacroText(\"/s \"" + msg + "\"");
                        SetNextRebirthAllowed();
                        return RunStatus.Success;
                    }
                    return RunStatus.Failure;

                });
        }
        Composite ResHealer()
        {
            return
                new Action(ret =>
                {

                    var ResHealTarget = Healers.FirstOrDefault();
                    string msg = StyxWoW.Me + " is ressing " + ResHealTarget;
                    if (ResHealTarget != null && SpellManager.CanCast(REBIRTH))
                    {
                        SpellManager.Cast(REBIRTH, ResHealTarget);
                        Logging.Write(Colors.Red, "Ressing Healer " + ResHealTarget.Name);
                        Lua.DoString("RunMacroText(\"/s \"" + msg + "\"");
                        SetNextRebirthAllowed();
                        return RunStatus.Success;
                    }
                    return RunStatus.Failure;
                });
        }
        #endregion

        #region Buff Checks

        public bool buffExists(int Buff, WoWUnit onTarget)
        {
            if (onTarget != null)
            {
                var Results = onTarget.GetAuraById(Buff);
                if (Results != null)
                    return true;
            }
            return false;
        }

        public double buffTimeLeft(int Buff, WoWUnit onTarget)
        {
            if (onTarget != null)
            {
                var Results = onTarget.GetAuraById(Buff);
                if (Results != null)
                {
                    if (Results.TimeLeft.TotalMilliseconds > 0)
                        return Results.TimeLeft.TotalMilliseconds;
                }
            }
            return 0;
        }

        public bool buffExists(string Buff, WoWUnit onTarget)
        {
            if (onTarget != null)
            {
                var Results = onTarget.GetAuraByName(Buff);
                if (Results != null)
                    return true;
            }
            return false;
        }

        public double buffTimeLeft(string Buff, WoWUnit onTarget)
        {
            if (onTarget != null)
            {
                var Results = onTarget.GetAuraByName(Buff);
                if (Results != null)
                {
                    if (Results.TimeLeft.TotalMilliseconds > 0)
                        return Results.TimeLeft.TotalMilliseconds;
                }
            }
            return 0;
        }



        public uint buffStackCount(int Buff, WoWUnit onTarget)
        {
            if (onTarget != null)
            {
                var Results = onTarget.GetAuraById(Buff);
                if (Results != null)
                    return Results.StackCount;
            }
            return 0;
        }
        public uint buffStackCount(string Buff, WoWUnit onTarget)
        {
            if (onTarget != null)
            {
                var Results = onTarget.GetAuraByName(Buff);
                if (Results != null)
                    return Results.StackCount;
            }
            return 0;
        }
        #endregion

        #region Cache Checks
        public IEnumerable<WoWAura> cachedAuras = new List<WoWAura>();
        public IEnumerable<WoWAura> cachedTargetAuras = new List<WoWAura>();
        public void getCachedAuras()
        {
            if (Me.CurrentTarget != null)
                cachedTargetAuras = Me.CurrentTarget.GetAllAuras();
            cachedAuras = Me.GetAllAuras();
        }
        #endregion

        #region Cooldown Checks
        private Dictionary<WoWSpell, long> Cooldowns = new Dictionary<WoWSpell, long>();
        public TimeSpan cooldownLeft(int Spell)
        {
            SpellFindResults Results;
            if (SpellManager.FindSpell(Spell, out Results))
            {
                WoWSpell Result = Results.Override ?? Results.Original;
                if (Cooldowns.TryGetValue(Result, out lastUsed))
                {
                    if (DateTime.Now.Ticks < lastUsed)
                        return Result.CooldownTimeLeft;
                    return TimeSpan.MaxValue;
                }
            }
            return TimeSpan.MaxValue;
        }
        public TimeSpan cooldownLeft(string Spell)
        {
            SpellFindResults Results;
            if (SpellManager.FindSpell(Spell, out Results))
            {
                WoWSpell Result = Results.Override ?? Results.Original;
                if (Cooldowns.TryGetValue(Result, out lastUsed))
                {
                    if (DateTime.Now.Ticks < lastUsed)
                        return Result.CooldownTimeLeft;
                    return TimeSpan.MaxValue;
                }
            }
            return TimeSpan.MaxValue;
        }
        long lastUsed;
        public int lastCast;
        public bool onCooldown(int Spell)
        {
            SpellFindResults Results;
            if (SpellManager.FindSpell(Spell, out Results))
            {
                WoWSpell Result = Results.Override ?? Results.Original;
                if (Cooldowns.TryGetValue(Result, out lastUsed))
                {
                    if (DateTime.Now.Ticks < lastUsed)
                        return Result.Cooldown;
                    return false;
                }
            }
            return false;
        }
        public bool onCooldown(string Spell)
        {
            SpellFindResults Results;
            if (SpellManager.FindSpell(Spell, out Results))
            {
                WoWSpell Result = Results.Override ?? Results.Original;
                if (Cooldowns.TryGetValue(Result, out lastUsed))
                {
                    if (DateTime.Now.Ticks < lastUsed)
                        return Result.Cooldown;
                    return false;
                }
            }
            return false;
        }
        public TimeSpan spellCooldownLeft(int Spell, bool useTracker = false)
        {
            if (useTracker)
                return cooldownLeft(Spell);
            SpellFindResults results;
            if (SpellManager.FindSpell(Spell, out results))
            {
                if (results.Override != null)
                    return results.Override.CooldownTimeLeft;
                return results.Override.CooldownTimeLeft;
            }
            return TimeSpan.MaxValue;
        }
        public TimeSpan spellCooldownLeft(string Spell, bool useTracker = false)
        {
            if (useTracker)
                return cooldownLeft(Spell);
            SpellFindResults results;
            if (SpellManager.FindSpell(Spell, out results))
            {
                if (results.Override != null)
                    return results.Override.CooldownTimeLeft;
                return results.Override.CooldownTimeLeft;
            }
            return TimeSpan.MaxValue;
        }
        public bool spellOnCooldown(int Spell, bool useTracker = false)
        {
            if (useTracker)
                return !onCooldown(Spell);
            SpellFindResults results;
            if (SpellManager.FindSpell(Spell, out results))
                return results.Override != null ? results.Override.Cooldown : results.Original.Cooldown;
            return false;
        }
        public bool spellOnCooldown(string Spell, bool useTracker = false)
        {
            if (useTracker)
                return !onCooldown(Spell);
            SpellFindResults results;
            if (SpellManager.FindSpell(Spell, out results))
                return results.Override != null ? results.Override.Cooldown : results.Original.Cooldown;
            return false;
        }
        #endregion

        #region Debuff Checks

        public bool debuffExists(int Debuff, WoWUnit onTarget)
        {
            if (onTarget != null)
            {
                WoWAura aura = onTarget.GetAllAuras().FirstOrDefault(a => a.SpellId == Debuff && a.CreatorGuid == Me.Guid);
                if (aura != null)
                {
                    return true;
                }
            }
            return false;
        }

        public double debuffTimeLeft(int Debuff, WoWUnit onTarget)
        {
            if (onTarget != null)
            {
                WoWAura aura = onTarget.GetAllAuras().FirstOrDefault(a =>
                    a.SpellId == Debuff
                    && a.CreatorGuid == Me.Guid);

                if (aura == null)
                {
                    return 0;
                }
                return aura.TimeLeft.TotalMilliseconds;
            }
            return 0;
        }

        public uint debuffStackCount(int Debuff, WoWUnit onTarget)
        {
            if (onTarget != null)
            {
                WoWAura aura = onTarget.GetAllAuras().FirstOrDefault(a =>
                    a.SpellId == Debuff
                    && a.CreatorGuid == Me.Guid);

                if (aura == null)
                {
                    return 0;
                }
                return aura.StackCount;
            }
            return 0;
        }
        public bool debuffExists(string Debuff, WoWUnit onTarget)
        {
            if (onTarget != null)
            {
                WoWAura aura = onTarget.GetAllAuras().FirstOrDefault(a => a.Name == Debuff && a.CreatorGuid == Me.Guid);
                if (aura != null)
                {
                    return true;
                }
            }
            return false;
        }

        public double debuffTimeLeft(string Debuff, WoWUnit onTarget)
        {
            if (onTarget != null)
            {
                WoWAura aura = onTarget.GetAllAuras().FirstOrDefault(a =>
                    a.Name == Debuff
                    && a.CreatorGuid == Me.Guid);

                if (aura == null)
                {
                    return 0;
                }
                return aura.TimeLeft.TotalMilliseconds;
            }
            return 0;
        }

        public uint debuffStackCount(string Debuff, WoWUnit onTarget)
        {
            if (onTarget != null)
            {
                WoWAura aura = onTarget.GetAllAuras().FirstOrDefault(a =>
                    a.Name == Debuff
                    && a.CreatorGuid == Me.Guid);

                if (aura == null)
                {
                    return 0;
                }
                return aura.StackCount;
            }
            return 0;
        }
        #endregion

        #region Timer Checks
        public bool isTargetDummy
        {
            get
            {
                return Me.CurrentTarget.Name.Contains("Dummy");
            }
        }
        private int conv_Date2Timestam(DateTime _time)
        {
            var date1 = new DateTime(1970, 1, 1);
            DateTime date2 = _time;
            var ts = new TimeSpan(date2.Ticks - date1.Ticks);
            return (Convert.ToInt32(ts.TotalSeconds));
        }
        private uint current_life;
        private int current_time;
        private ulong guid;
        private uint first_life;
        private uint first_life_max;
        private int first_time;
        public long targetExistence(WoWUnit onTarget)
        {
            if (onTarget == null) return 0;
            if (isTargetDummy) return 9999;
            if (onTarget.CurrentHealth == 0 || onTarget.IsDead || !onTarget.IsValid || !onTarget.IsAlive)
                return 0;
            if (guid != onTarget.Guid)
            {
                guid = onTarget.Guid;
                first_life = onTarget.CurrentHealth;
                first_life_max = onTarget.MaxHealth;
                first_time = conv_Date2Timestam(DateTime.Now);
            }
            current_life = onTarget.CurrentHealth;
            current_time = conv_Date2Timestam(DateTime.Now);
            var time_diff = current_time - first_time;
            var hp_diff = first_life - current_life;
            if (hp_diff > 0)
            {
                var full_time = time_diff * first_life_max / hp_diff;
                var past_first_time = (first_life_max - first_life) * time_diff / hp_diff;
                var calc_time = first_time - past_first_time + full_time - current_time;
                if (calc_time < 1) calc_time = 99;
                var time_to_die = calc_time;
                var fight_length = full_time;
                return time_to_die;
            }
            if (hp_diff < 0)
            {
                guid = onTarget.Guid;
                first_life = onTarget.CurrentHealth;
                first_life_max = onTarget.MaxHealth;
                first_time = conv_Date2Timestam(DateTime.Now);
                return -1;
            }
            if (current_life == first_life_max)
                return 9999;
            return -1;
        }
        #endregion

        #region useitems
        private static bool CanUseEquippedItem(WoWItem item)
        {
            // Check for engineering tinkers!
            string itemSpell = Lua.GetReturnVal<string>("return GetItemSpell(" + item.Entry + ")", 0);
            if (string.IsNullOrEmpty(itemSpell))
                return false;


            return item.Usable && item.Cooldown <= 0;
        }

        Composite Trinket1()
        {
            return
                    new Action(ret =>
                    {
                        var firstTrinket = StyxWoW.Me.Inventory.Equipped.Trinket1;

                        if (SettingsBear.myPrefs.Trinket1Use == SettingsBear.TrinketsUse.Below_HealthPercent
                            && Me.HealthPercent <= SettingsBear.myPrefs.trinket1hppercent
                            && firstTrinket != null
                            && CanUseEquippedItem(firstTrinket))
                        {
                            firstTrinket.Use();
                            SetNextNextTrinketTimeAllowed();
                        }
                        if (SettingsBear.myPrefs.Trinket1Use == SettingsBear.TrinketsUse.CrowdControlled
                            && IsCrowdControlledPlayer(Me)
                            && firstTrinket != null
                            && CanUseEquippedItem(firstTrinket))
                        {
                            firstTrinket.Use();
                            SetNextNextTrinketTimeAllowed();
                        }
                        if (SettingsBear.myPrefs.Trinket1Use == SettingsBear.TrinketsUse.DPS_Boost
                            && IsWoWBoss(Me.CurrentTarget)
                            && firstTrinket != null
                            && CanUseEquippedItem(firstTrinket))
                        {
                            firstTrinket.Use();
                            SpellManager.ClickRemoteLocation(Me.CurrentTarget.Location);
                            SetNextNextTrinketTimeAllowed();
                        }
                        return RunStatus.Failure;
                    });
        }
        Composite Trinket2()
        {
            return
                    new Action(ret =>
                    {
                        var secondTrinket = StyxWoW.Me.Inventory.Equipped.Trinket2;

                        if (SettingsBear.myPrefs.Trinket2Use == SettingsBear.TrinketsUse.Below_HealthPercent
                            && Me.HealthPercent <= SettingsBear.myPrefs.trinket2hppercent
                            && secondTrinket != null
                            && CanUseEquippedItem(secondTrinket))
                        {
                            secondTrinket.Use();
                            SetNextNextTrinketTimeAllowed();
                        }
                        if (SettingsBear.myPrefs.Trinket2Use == SettingsBear.TrinketsUse.CrowdControlled
                            && IsCrowdControlledPlayer(Me)
                            && secondTrinket != null
                            && CanUseEquippedItem(secondTrinket))
                        {
                            secondTrinket.Use();
                            SetNextNextTrinketTimeAllowed();
                        }
                        if (SettingsBear.myPrefs.Trinket2Use == SettingsBear.TrinketsUse.DPS_Boost
                            && IsWoWBoss(Me.CurrentTarget)
                            && secondTrinket != null
                            && CanUseEquippedItem(secondTrinket))
                        {
                            secondTrinket.Use();
                            SpellManager.ClickRemoteLocation(Me.CurrentTarget.Location);
                            SetNextNextTrinketTimeAllowed();
                        }
                        return RunStatus.Failure;

                    });
        }
        Composite HealthstoneBear()
        {
            return 
                new Action(ret =>
                {
                    var hstone = ObjectManager.GetObjectsOfType<WoWItem>().FirstOrDefault(item => item.Entry == 5512);
                    if (hstone != null && hstone.Usable)
                    {
                        hstone.Use();
                        Logging.Write("Using Healthstone");
                        SetNextHealthstoneUseAllowed();
                    }
                    return RunStatus.Failure;
                });
        }
        Composite HealthstoneCat()
        {
            return
                new Action(ret =>
                {
                    var hstone = ObjectManager.GetObjectsOfType<WoWItem>().FirstOrDefault(item => item.Entry == 5512);
                    if (hstone != null && hstone.Usable)
                    {
                        hstone.Use();
                        Logging.Write("Using Healthstone");
                        SetNextHealthstoneUseAllowed();
                    }
                    return RunStatus.Failure;
                });
        }
        Composite AlchemyFlask()
        {
            return
                new Action(ret =>
                {
                    var alchflask = ObjectManager.GetObjectsOfType<WoWItem>().FirstOrDefault(item => item.Entry == 75525);
                    if (alchflask != null && alchflask.Usable && alchflask.Cooldown <= 0)
                    {
                        alchflask.Use();
                        SetNextBuffAllowed();
                    }
                    return RunStatus.Failure;
                });
        }
        Composite CrystalOfInsanity()
        {
            return new Action(ret =>
            {
                var crystal = ObjectManager.GetObjectsOfType<WoWItem>().FirstOrDefault(item => item.Entry == 86569);
                if (crystal != null && crystal.Usable && crystal.Cooldown <= 0)
                {
                    crystal.Use();
                    SetNextBuffAllowed();
                }
                return RunStatus.Failure;
            });
        }
        Composite FlaskOfTheEarth()
        {
            return new Action(ret =>
            {
                
                var earth = ObjectManager.GetObjectsOfType<WoWItem>().FirstOrDefault(item => item.Entry == FLASK_OF_THE_EARTH);
                if (earth != null 
                    && earth.Usable
                    && SettingsCommon.myPrefs.AutoUseFlaskOfTheEarth == SettingsCommon.FlaskUse.Dungeons
                    && (Me.CurrentMap.IsDungeon || Me.CurrentMap.IsInstance))
                {
                    earth.Use();
                    SetNextBuffAllowed();
                }
                if (earth != null
                    && earth.Usable
                    && SettingsCommon.myPrefs.AutoUseFlaskOfTheEarth == SettingsCommon.FlaskUse.Raids_but_not_LFR
                    && Me.CurrentMap.IsRaid
                    && !Me.GroupInfo.IsInLfgParty)
                {
                    if (buffExists(CRYSTAL_OF_INSANITY_BUFF, Me))
                    {
                        Lua.DoString("RunMacroText(\"/cancelaura Visions of Insanity\")");
                        Logging.Write(Colors.Fuchsia, "Removing Crystal of Insanity Buff");
                    }
                    earth.Use();
                    SetNextBuffAllowed();
                }
                if (earth != null
                    && earth.Usable
                    && SettingsCommon.myPrefs.AutoUseFlaskOfTheEarth == SettingsCommon.FlaskUse.Raids
                    && Me.CurrentMap.IsRaid)
                {
                    if (buffExists(CRYSTAL_OF_INSANITY_BUFF, Me))
                    {
                        Lua.DoString("RunMacroText(\"/cancelaura Visions of Insanity\")");
                        Logging.Write(Colors.Fuchsia, "Removing Crystal of Insanity Buff");
                    }
                    earth.Use();
                    SetNextBuffAllowed();
                }
                return RunStatus.Failure;
            });
        }
        Composite FlaskOfSpringBlossom()
        {
            return new Action(ret =>
            {
                var earth = ObjectManager.GetObjectsOfType<WoWItem>().FirstOrDefault(item => item.Entry == FLASK_OF_SPRING_BLOSSOMS);
                if (earth != null
                    && earth.Usable
                    && SettingsCommon.myPrefs.AutoUseFlaskOfSpringBlossom == SettingsCommon.FlaskUse.Dungeons
                    && (Me.CurrentMap.IsDungeon || Me.CurrentMap.IsInstance))
                {
                    if (buffExists(CRYSTAL_OF_INSANITY_BUFF, Me))
                    {
                        Lua.DoString("RunMacroText(\"/cancelaura Visions of Insanity\")");
                        Logging.Write(Colors.Fuchsia, "Removing Crystal of Insanity Buff");
                    }
                    earth.Use();
                    SetNextBuffAllowed();
                }
                if (earth != null
                    && earth.Usable
                    && SettingsCommon.myPrefs.AutoUseFlaskOfSpringBlossom == SettingsCommon.FlaskUse.Raids_but_not_LFR
                    && Me.CurrentMap.IsRaid
                    && !Me.GroupInfo.IsInLfgParty)
                {
                    if (buffExists(CRYSTAL_OF_INSANITY_BUFF, Me))
                    {
                        Lua.DoString("RunMacroText(\"/cancelaura Visions of Insanity\")");
                        Logging.Write(Colors.Fuchsia, "Removing Crystal of Insanity Buff");
                    }
                    earth.Use();
                    SetNextBuffAllowed();
                }
                if (earth != null
                    && earth.Usable
                    && SettingsCommon.myPrefs.AutoUseFlaskOfSpringBlossom == SettingsCommon.FlaskUse.Raids
                    && Me.CurrentMap.IsRaid)
                {
                    if (buffExists(CRYSTAL_OF_INSANITY_BUFF, Me))
                    {
                        Lua.DoString("RunMacroText(\"/cancelaura Visions of Insanity\")");
                        Logging.Write(Colors.Fuchsia, "Removing Crystal of Insanity Buff");
                    }
                    earth.Use();
                    SetNextBuffAllowed();
                }
                return RunStatus.Failure;
            });
        }
        #endregion

        #region flask buffs
        //flask id's
        public int CRYSTAL_OF_INSANITY_ITEM = 86569;
        public int FLASK_OF_THE_WARM_SUN = 76085;
        public int FLASK_OF_WINTERS_BITE = 76088;
        public int FLASK_OF_THE_EARTH = 76087;
        public int FLASK_OF_SPRING_BLOSSOMS = 76084;
        public int FLASK_OF_FALING_LEAVES = 76086;

        //flaskbuff id's
        public int CRYSTAL_OF_INSANITY_BUFF = 127230;
        public int Flask_OF_THE_EARTH_BUFF = 105694;
        public int Flask_OF_THE_WARM_SUN_BUFF = 105691;
        public int FLASK_OF_WINTERS_BITE_BUFF = 105696;
        public int FLASK_OF_FALLING_LEAVES_BUFF = 105693;
        public int FLASK_OF_SPRING_BLOSSOMS_BUFF = 105689;

        public bool HaveFlaskBuff
        {
            get
            {
                return buffExists(Flask_OF_THE_EARTH_BUFF, Me)
                    || buffExists(Flask_OF_THE_WARM_SUN_BUFF, Me)
                    || buffExists(FLASK_OF_WINTERS_BITE_BUFF, Me)
                    || buffExists(FLASK_OF_FALLING_LEAVES_BUFF, Me)
                    || buffExists(FLASK_OF_SPRING_BLOSSOMS_BUFF, Me);
            }
        }
        #endregion

        #region next buff allowed
        private DateTime nextBuffAllowed;

        public void SetNextBuffAllowed()
        {
            nextBuffAllowed = DateTime.Now + new TimeSpan(0, 0, 0, 0, 1500);
        }
        #endregion

        #region myRange
        public float myPullRange
        {
            get
            {
                if (!SpellManager.HasSpell("Cat Form")) { return 35; }
                if (SpellManager.HasSpell(FAERIE_FIRE) && !SpellManager.HasSpell(FAERIE_SWARM) && !spellOnCooldown(FAERIE_FIRE)) { return 30; }
                if (SpellManager.HasSpell(FAERIE_SWARM) && !spellOnCooldown(FAERIE_SWARM)) { return 30; }
                if (SpellManager.HasSpell(GROWL) && !spellOnCooldown(GROWL) && Me.Shapeshift == ShapeshiftForm.Bear && !Me.CurrentTarget.IsPlayer) { return 30; }
                return 4;
            }
        }
        public float myMeleeRange
        {
            get
            {
                if (Me.CurrentTarget.IsPlayer) { return 2.5f; }
                return 4f;
            }
        }
        #endregion

    }
}
